#include "YangProcess.h"





#define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \
DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | \
DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \
DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)

#define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \
WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | \
WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | \
WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN | \
STANDARD_RIGHTS_REQUIRED)

#define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | \
GENERIC_EXECUTE | GENERIC_ALL)

BOOL AddAceToWindowStation(HWINSTA hwinsta, PSID psid);

BOOL AddAceToDesktop(HDESK hdesk, PSID psid);

BOOL GetLogonSID(HANDLE hToken, PSID* ppsid);

VOID FreeLogonSID(PSID* ppsid);

BOOL StartInteractiveClientProcess(
    LPSTR lpszUsername,    // client to log on
    LPSTR lpszDomain,      // domain of client's account
    LPSTR lpszPassword,    // client's password
    LPSTR lpCommandLine    // command line to execute
)
{
    HANDLE      hToken;
    HDESK       hdesk = NULL;
    HWINSTA     hwinsta = NULL, hwinstaSave = NULL;
    PROCESS_INFORMATION pi;
    PSID pSid = NULL;
    STARTUPINFO si;
    BOOL bResult = FALSE;

    // Log the client on to the local computer.

    if (!LogonUser(
        lpszUsername,
        lpszDomain,
        lpszPassword,
        LOGON32_LOGON_INTERACTIVE,
        LOGON32_PROVIDER_DEFAULT,
        &hToken))
    {
        goto Cleanup;
    }

    // Save a handle to the caller's current window station.

    if ((hwinstaSave = GetProcessWindowStation()) == NULL)
        goto Cleanup;

    // Get a handle to the interactive window station.

    hwinsta = OpenWindowStation(
        ("winsta0"),                   // the interactive window station 
        FALSE,                       // handle is not inheritable
        READ_CONTROL | WRITE_DAC);   // rights to read/write the DACL

    if (hwinsta == NULL)
        goto Cleanup;

    // To get the correct default desktop, set the caller's 
    // window station to the interactive window station.

    if (!SetProcessWindowStation(hwinsta))
        goto Cleanup;

    // Get a handle to the interactive desktop.

    hdesk = OpenDesktop(
        ("default"),     // the interactive window station 
        0,             // no interaction with other desktop processes
        FALSE,         // handle is not inheritable
        READ_CONTROL | // request the rights to read and write the DACL
        WRITE_DAC |
        DESKTOP_WRITEOBJECTS |
        DESKTOP_READOBJECTS);

    // Restore the caller's window station.

    if (!SetProcessWindowStation(hwinstaSave))
        goto Cleanup;

    if (hdesk == NULL)
        goto Cleanup;

    // Get the SID for the client's logon session.

    if (!GetLogonSID(hToken, &pSid))
        goto Cleanup;

    // Allow logon SID full access to interactive window station.

    if (!AddAceToWindowStation(hwinsta, pSid))
        goto Cleanup;

    // Allow logon SID full access to interactive desktop.

    if (!AddAceToDesktop(hdesk, pSid))
        goto Cleanup;

    // Impersonate client to ensure access to executable file.

    if (!ImpersonateLoggedOnUser(hToken))
        goto Cleanup;

    // Initialize the STARTUPINFO structure.
    // Specify that the process runs in the interactive desktop.

    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);
    si.lpDesktop = TEXT("winsta0\\default");

    // Launch the process in the client's logon session.

    bResult = CreateProcessAsUser(
        hToken,            // client's access token
        NULL,              // file to execute
        lpCommandLine,     // command line
        NULL,              // pointer to process SECURITY_ATTRIBUTES
        NULL,              // pointer to thread SECURITY_ATTRIBUTES
        FALSE,             // handles are not inheritable
        NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,   // creation flags
        NULL,              // pointer to new environment block 
        NULL,              // name of current directory 
        &si,               // pointer to STARTUPINFO structure
        &pi                // receives information about new process
    );

    // End impersonation of client.

    RevertToSelf();

    if (bResult && pi.hProcess != INVALID_HANDLE_VALUE)
    {
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
    }

    if (pi.hThread != INVALID_HANDLE_VALUE)
        CloseHandle(pi.hThread);

Cleanup:

    if (hwinstaSave != NULL)
        SetProcessWindowStation(hwinstaSave);

    // Free the buffer for the logon SID.

    if (pSid)
        FreeLogonSID(&pSid);

    // Close the handles to the interactive window station and desktop.

    if (hwinsta)
        CloseWindowStation(hwinsta);

    if (hdesk)
        CloseDesktop(hdesk);

    // Close the handle to the client's access token.

    if (hToken != INVALID_HANDLE_VALUE)
        CloseHandle(hToken);

    return bResult;
}

BOOL AddAceToWindowStation(HWINSTA hwinsta, PSID psid)
{
    ACCESS_ALLOWED_ACE* pace = NULL;
    ACL_SIZE_INFORMATION aclSizeInfo;
    BOOL                 bDaclExist;
    BOOL                 bDaclPresent;
    BOOL                 bSuccess = FALSE;
    DWORD                dwNewAclSize;
    DWORD                dwSidSize = 0;
    DWORD                dwSdSizeNeeded;
    PACL                 pacl;
    PACL                 pNewAcl = NULL;
    PSECURITY_DESCRIPTOR psd = NULL;
    PSECURITY_DESCRIPTOR psdNew = NULL;
    PVOID                pTempAce;
    SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
    unsigned int         i;

    __try
    {
        // Obtain the DACL for the window station.

        if (!GetUserObjectSecurity(
            hwinsta,
            &si,
            psd,
            dwSidSize,
            &dwSdSizeNeeded)
            )
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
            {
                psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
                    GetProcessHeap(),
                    HEAP_ZERO_MEMORY,
                    dwSdSizeNeeded);

                if (psd == NULL)
                    __leave;

                psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
                    GetProcessHeap(),
                    HEAP_ZERO_MEMORY,
                    dwSdSizeNeeded);

                if (psdNew == NULL)
                    __leave;

                dwSidSize = dwSdSizeNeeded;

                if (!GetUserObjectSecurity(
                    hwinsta,
                    &si,
                    psd,
                    dwSidSize,
                    &dwSdSizeNeeded)
                    )
                    __leave;
            }
            else
                __leave;

        // Create a new DACL.

        if (!InitializeSecurityDescriptor(
            psdNew,
            SECURITY_DESCRIPTOR_REVISION)
            )
            __leave;

        // Get the DACL from the security descriptor.

        if (!GetSecurityDescriptorDacl(
            psd,
            &bDaclPresent,
            &pacl,
            &bDaclExist)
            )
            __leave;

        // Initialize the ACL.

        ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
        aclSizeInfo.AclBytesInUse = sizeof(ACL);

        // Call only if the DACL is not NULL.

        if (pacl != NULL)
        {
            // get the file ACL size info
            if (!GetAclInformation(
                pacl,
                (LPVOID)&aclSizeInfo,
                sizeof(ACL_SIZE_INFORMATION),
                AclSizeInformation)
                )
                __leave;
        }

        // Compute the size of the new ACL.

        dwNewAclSize = aclSizeInfo.AclBytesInUse +
            (2 * sizeof(ACCESS_ALLOWED_ACE)) + (2 * GetLengthSid(psid)) -
            (2 * sizeof(DWORD));

        // Allocate memory for the new ACL.

        pNewAcl = (PACL)HeapAlloc(
            GetProcessHeap(),
            HEAP_ZERO_MEMORY,
            dwNewAclSize);

        if (pNewAcl == NULL)
            __leave;

        // Initialize the new DACL.

        if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
            __leave;

        // If DACL is present, copy it to a new DACL.

        if (bDaclPresent)
        {
            // Copy the ACEs to the new ACL.
            if (aclSizeInfo.AceCount)
            {
                for (i = 0; i < aclSizeInfo.AceCount; i++)
                {
                    // Get an ACE.
                    if (!GetAce(pacl, i, &pTempAce))
                        __leave;

                    // Add the ACE to the new ACL.
                    if (!AddAce(
                        pNewAcl,
                        ACL_REVISION,
                        MAXDWORD,
                        pTempAce,
                        ((PACE_HEADER)pTempAce)->AceSize)
                        )
                        __leave;
                }
            }
        }

        // Add the first ACE to the window station.

        pace = (ACCESS_ALLOWED_ACE*)HeapAlloc(
            GetProcessHeap(),
            HEAP_ZERO_MEMORY,
            sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) -
            sizeof(DWORD));

        if (pace == NULL)
            __leave;

        pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
        pace->Header.AceFlags = CONTAINER_INHERIT_ACE |
            INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
        pace->Header.AceSize = LOWORD(sizeof(ACCESS_ALLOWED_ACE) +
            GetLengthSid(psid) - sizeof(DWORD));
        pace->Mask = GENERIC_ACCESS;

        if (!CopySid(GetLengthSid(psid), &pace->SidStart, psid))
            __leave;

        if (!AddAce(
            pNewAcl,
            ACL_REVISION,
            MAXDWORD,
            (LPVOID)pace,
            pace->Header.AceSize)
            )
            __leave;

        // Add the second ACE to the window station.

        pace->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE;
        pace->Mask = WINSTA_ALL;

        if (!AddAce(
            pNewAcl,
            ACL_REVISION,
            MAXDWORD,
            (LPVOID)pace,
            pace->Header.AceSize)
            )
            __leave;

        // Set a new DACL for the security descriptor.

        if (!SetSecurityDescriptorDacl(
            psdNew,
            TRUE,
            pNewAcl,
            FALSE)
            )
            __leave;

        // Set the new security descriptor for the window station.

        if (!SetUserObjectSecurity(hwinsta, &si, psdNew))
            __leave;

        // Indicate success.

        bSuccess = TRUE;
    }
    __finally
    {
        // Free the allocated buffers.

        if (pace != NULL)
            HeapFree(GetProcessHeap(), 0, (LPVOID)pace);

        if (pNewAcl != NULL)
            HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);

        if (psd != NULL)
            HeapFree(GetProcessHeap(), 0, (LPVOID)psd);

        if (psdNew != NULL)
            HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew);
    }

    return bSuccess;

}

BOOL AddAceToDesktop(HDESK hdesk, PSID psid)
{
    ACL_SIZE_INFORMATION aclSizeInfo;
    BOOL                 bDaclExist;
    BOOL                 bDaclPresent;
    BOOL                 bSuccess = FALSE;
    DWORD                dwNewAclSize;
    DWORD                dwSidSize = 0;
    DWORD                dwSdSizeNeeded;
    PACL                 pacl;
    PACL                 pNewAcl = NULL;
    PSECURITY_DESCRIPTOR psd = NULL;
    PSECURITY_DESCRIPTOR psdNew = NULL;
    PVOID                pTempAce;
    SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
    unsigned int         i;

    __try
    {
        // Obtain the security descriptor for the desktop object.

        if (!GetUserObjectSecurity(
            hdesk,
            &si,
            psd,
            dwSidSize,
            &dwSdSizeNeeded))
        {
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
            {
                psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
                    GetProcessHeap(),
                    HEAP_ZERO_MEMORY,
                    dwSdSizeNeeded);

                if (psd == NULL)
                    __leave;

                psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
                    GetProcessHeap(),
                    HEAP_ZERO_MEMORY,
                    dwSdSizeNeeded);

                if (psdNew == NULL)
                    __leave;

                dwSidSize = dwSdSizeNeeded;

                if (!GetUserObjectSecurity(
                    hdesk,
                    &si,
                    psd,
                    dwSidSize,
                    &dwSdSizeNeeded)
                    )
                    __leave;
            }
            else
                __leave;
        }

        // Create a new security descriptor.

        if (!InitializeSecurityDescriptor(
            psdNew,
            SECURITY_DESCRIPTOR_REVISION)
            )
            __leave;

        // Obtain the DACL from the security descriptor.

        if (!GetSecurityDescriptorDacl(
            psd,
            &bDaclPresent,
            &pacl,
            &bDaclExist)
            )
            __leave;

        // Initialize.

        ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
        aclSizeInfo.AclBytesInUse = sizeof(ACL);

        // Call only if NULL DACL.

        if (pacl != NULL)
        {
            // Determine the size of the ACL information.

            if (!GetAclInformation(
                pacl,
                (LPVOID)&aclSizeInfo,
                sizeof(ACL_SIZE_INFORMATION),
                AclSizeInformation)
                )
                __leave;
        }

        // Compute the size of the new ACL.

        dwNewAclSize = aclSizeInfo.AclBytesInUse +
            sizeof(ACCESS_ALLOWED_ACE) +
            GetLengthSid(psid) - sizeof(DWORD);

        // Allocate buffer for the new ACL.

        pNewAcl = (PACL)HeapAlloc(
            GetProcessHeap(),
            HEAP_ZERO_MEMORY,
            dwNewAclSize);

        if (pNewAcl == NULL)
            __leave;

        // Initialize the new ACL.

        if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
            __leave;

        // If DACL is present, copy it to a new DACL.

        if (bDaclPresent)
        {
            // Copy the ACEs to the new ACL.
            if (aclSizeInfo.AceCount)
            {
                for (i = 0; i < aclSizeInfo.AceCount; i++)
                {
                    // Get an ACE.
                    if (!GetAce(pacl, i, &pTempAce))
                        __leave;

                    // Add the ACE to the new ACL.
                    if (!AddAce(
                        pNewAcl,
                        ACL_REVISION,
                        MAXDWORD,
                        pTempAce,
                        ((PACE_HEADER)pTempAce)->AceSize)
                        )
                        __leave;
                }
            }
        }

        // Add ACE to the DACL.

        if (!AddAccessAllowedAce(
            pNewAcl,
            ACL_REVISION,
            DESKTOP_ALL,
            psid)
            )
            __leave;

        // Set new DACL to the new security descriptor.

        if (!SetSecurityDescriptorDacl(
            psdNew,
            TRUE,
            pNewAcl,
            FALSE)
            )
            __leave;

        // Set the new security descriptor for the desktop object.

        if (!SetUserObjectSecurity(hdesk, &si, psdNew))
            __leave;

        // Indicate success.

        bSuccess = TRUE;
    }
    __finally
    {
        // Free buffers.

        if (pNewAcl != NULL)
            HeapFree(GetProcessHeap(), 0, (LPVOID)pNewAcl);

        if (psd != NULL)
            HeapFree(GetProcessHeap(), 0, (LPVOID)psd);

        if (psdNew != NULL)
            HeapFree(GetProcessHeap(), 0, (LPVOID)psdNew);
    }

    return bSuccess;
}

BOOL GetLogonSID(HANDLE hToken, PSID* ppsid)
{
   BOOL bSuccess = FALSE;
   DWORD dwIndex;
   DWORD dwLength = 0;
   PTOKEN_GROUPS ptg = NULL;

 //  Verify the parameter passed in is not NULL. 
      if (NULL == ppsid)
         goto  Cleanup;

 //  Get required buffer size and allocate the TOKEN_GROUPS buffer. 

    if (!GetTokenInformation(
         hToken,          //  handle to the access token 
          TokenGroups,     //  get information about the token's groups  
(LPVOID) ptg,    //  pointer to TOKEN_GROUPS buffer 
           0 ,               //  size of buffer 
 & dwLength        //  receives required buffer size 
))
    {
       if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
          goto  Cleanup;

      ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
         HEAP_ZERO_MEMORY, dwLength);

       if (ptg == NULL)
          goto  Cleanup;
   }

 //  Get the token group information from the access token. 

    if (!GetTokenInformation(
         hToken,          //  handle to the access token 
          TokenGroups,     //  get information about the token's groups  
(LPVOID) ptg,    //  pointer to TOKEN_GROUPS buffer 
          dwLength,        //  size of buffer 
 & dwLength        //  receives required buffer size 
))
    {
       goto  Cleanup;
   }

 //  Loop through the groups to find the logon SID. 

    for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
       if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID)
 == SE_GROUP_LOGON_ID)
       {
       //  Found the logon SID; make a copy of it. 

         dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
* ppsid = (PSID)HeapAlloc(GetProcessHeap(),
                     HEAP_ZERO_MEMORY, dwLength);
          if (*ppsid == NULL)
              goto  Cleanup;
          if (!CopySid(dwLength,  *ppsid, ptg->Groups[dwIndex].Sid))
          {
             HeapFree(GetProcessHeap(),  0 , (LPVOID)*ppsid);
              goto  Cleanup;
        }
          break;
     }

   bSuccess = TRUE;

Cleanup:

 //  Free the buffer for the token groups. 

    if (ptg != NULL)
      HeapFree(GetProcessHeap(),  0 , (LPVOID)ptg);

    return  bSuccess;
 }

VOID FreeLogonSID(PSID* ppsid)
{
   HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
 }